package com.xltx.wechat.service.impl;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.xltx.wechat.common.constant.WechatConstant;
import com.xltx.wechat.model.AccessToken;
import com.xltx.wechat.model.WxUserInfo;
import com.xltx.wechat.properties.WechatProperties;
import com.xltx.wechat.service.WechatOAuth2Service;
import me.chanjar.weixin.common.api.WxConsts;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.awt.image.BufferedImage;
import java.util.Date;

/**
 * @ClassName WechatOAuth2ServiceImpl
 * @Date 2022/11/10 8:33
 * @Author xiaoliutx
 * @Description 网页授权OAuth2.0实现类
 */
@Service
public class WechatOAuth2ServiceImpl implements WechatOAuth2Service {

    @Resource
    private WechatProperties wechatProperties;

    @Override
    public String authCode() {
        return getAuthCode(wechatProperties.getRedirectUri(), WxConsts.OAuth2Scope.SNSAPI_USERINFO, String.valueOf(new Date().getTime()), "false");
    }

    @Override
    public String authCode(String state) {
        return getAuthCode(wechatProperties.getRedirectUri(), WxConsts.OAuth2Scope.SNSAPI_USERINFO, state, "false");
    }

    @Override
    public String authCode(String scope, String state) {
        return getAuthCode(wechatProperties.getRedirectUri(), scope, state, "false");
    }

    @Override
    public String authCode(String redirectUri, String scope, String state) {
        return getAuthCode(redirectUri, scope, state, "false");
    }

    @Override
    public String authCode(String redirectUri, String scope, String state, String forcePopup) {
        return getAuthCode(redirectUri, scope, state, forcePopup);
    }


    public String getAuthCode(String redirectUri, String scope, String state, String forcePopup) {
        if (StringUtils.isBlank(redirectUri)) {
            throw new NullPointerException("redirectUri is null");
        }
        if (StringUtils.isBlank(scope)) {
            throw new NullPointerException("scope is null");
        }
        return WechatConstant.AUTHORIZE
                .replace("APPID", wechatProperties.getAppId())
                .replace("REDIRECT_URI", redirectUri)
                .replace("SCOPE", scope)
                .replace("STATE", state)
                .replace("FORCEPOPUP", forcePopup);
    }


    @Override
    public String authQrCode(String redirectUri, String scope, String state) {
        if (StringUtils.isBlank(redirectUri)) {
            throw new NullPointerException("redirectUri is null");
        }
        if (StringUtils.isBlank(scope)) {
            throw new NullPointerException("scope is null");
        }
        return WechatConstant.QR_AUTH
                .replace("APPID", wechatProperties.getAppId())
                .replace("REDIRECT_URI", redirectUri)
                .replace("SCOPE", scope)
                .replace("STATE", state);
    }

    @Override
    public AccessToken accessToken(String code) {
        if (StringUtils.isBlank(code)) {
            throw new NullPointerException("code is null");
        }
        String url = WechatConstant.ACCESS_TOKEN
                .replace("APPID", wechatProperties.getAppId())
                .replace("APPSECRET", wechatProperties.getAppSecret())
                .replace("CODE", code);
        return getAccessToken(url);
    }

    @Override
    public AccessToken refreshToken(String refreshToken) {
        if (StringUtils.isBlank(refreshToken)) {
            throw new NullPointerException("refreshToken is null");
        }
        String url = WechatConstant.REFRESH_TOKEN
                .replace("APPID", wechatProperties.getAppId())
                .replace("REFRESH_TOKEN", refreshToken);
        return getAccessToken(url);
    }

    @Override
    public WxUserInfo userInfo(String accessToken, String openId) {
        if (StringUtils.isBlank(accessToken)) {
            throw new NullPointerException("accessToken is null");
        }
        if (StringUtils.isBlank(openId)) {
            throw new NullPointerException("openId is null");
        }
        String url = WechatConstant.SCOPE_SNSAPI_USERINFO
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String result = HttpUtil.get(url);
        if (StringUtils.isBlank(result)) {
            return null;
        }
        return JSONUtil.toBean(result, WxUserInfo.class);
    }

    @Override
    public Boolean checkAccessToken(String accessToken, String openId) {
        if (StringUtils.isBlank(accessToken)) {
            throw new NullPointerException("accessToken is null");
        }
        if (StringUtils.isBlank(openId)) {
            throw new NullPointerException("openId is null");
        }
        String url = WechatConstant.CHECK_ACCESS_TOKEN
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String result = HttpUtil.get(url);
        if (StringUtils.isBlank(result)) {
            return false;
        }
        JSONObject object = JSONUtil.parseObj(result);
        String errCode = object.getStr("errcode");
        return "0".equals(errCode);
    }


    /**
     * 获取AccessToken
     *
     * @param url 地址
     * @return AccessToken
     */
    private AccessToken getAccessToken(String url) {
        String result = HttpUtil.get(url);
        if (StringUtils.isBlank(result)) {
            return null;
        }
        AccessToken accessToken = JSONUtil.toBean(result, AccessToken.class);
        if (StringUtils.isBlank(accessToken.getAccessToken()) || StringUtils.isBlank(accessToken.getOpenid())) {
            return null;
        }
        return accessToken;
    }


    @Override
    public String getQrCode(String state) {
        return getQrCode(state, WechatConstant.AUTH_WAY_GZH, 250);
    }

    @Override
    public String getQrCode(String state, Integer size) {
        return getQrCode(state, WechatConstant.AUTH_WAY_GZH, size);
    }

    @Override
    public String getQrCode(String state, String authWay) {
        return getQrCode(state, WechatConstant.AUTH_WAY_GZH, 250);
    }

    @Override
    public String getQrCode(String state, String authWay, Integer size) {
        return ImgUtil.toBase64DataUri(getQrImage(state, authWay, size), ImgUtil.IMAGE_TYPE_PNG);
    }

    /**
     * 获取验证二维码图片
     *
     * @param state state
     * @return 图片
     */
    public BufferedImage getQrImage(String state, String authWay, Integer size) {
        String content;
        if (WechatConstant.AUTH_WAY_GZH.equals(authWay)) {
            content = authCode(wechatProperties.getRedirectUri(), WxConsts.OAuth2Scope.SNSAPI_USERINFO, state);
        } else {
            content = authQrCode(wechatProperties.getRedirectUri(), WxConsts.QrConnectScope.SNSAPI_LOGIN, state);
        }
        return QrCodeUtil.generate(content, QrConfig.create().setWidth(size).setHeight(size));
    }

}
